package org.springframework.security.config.annotation.web.configurers;

import org.springframework.security.config.annotation.web.HttpSecurityBuilder;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.context.*;
import org.springframework.security.web.session.ForceEagerSessionCreationFilter;

/**
 * @author Dillon
 * @date 2024/7/10
 * @slogan 致敬大师 致敬未来的你
 * @desc 登录缓存配置类 初始化并配置自定义缓存
 */
public final class SecurityContextConfigurer<H extends HttpSecurityBuilder<H>>
		extends AbstractHttpConfigurer<SecurityContextConfigurer<H>, H> {

	/**
	 * 是否需要显示保存（显示执行缓存持久化）
	 * 默认为真 使用 {@link SecurityContextHolderFilter}
	 */
	private boolean requireExplicitSave = true;

	/**
	 * 构造函数
	 */
	public SecurityContextConfigurer() {
	}

	/**
	 * 将持久化实现类设置到 构建共享对象中 方便后续使用
	 *
	 * @param securityContextRepository 持久化对象
	 * @return 当前对象
	 */
	public SecurityContextConfigurer<H> securityContextRepository(SecurityContextRepository securityContextRepository) {
		getBuilder().setSharedObject(SecurityContextRepository.class, securityContextRepository);
		return this;
	}

	/**
	 * 设置是否显示持久化登录成功缓存 默认为真
	 *
	 * @param requireExplicitSave 设置值
	 * @return 当前对象
	 */
	public SecurityContextConfigurer<H> requireExplicitSave(boolean requireExplicitSave) {
		this.requireExplicitSave = requireExplicitSave;
		return this;
	}

	/**
	 * 获取是否显示持久化登录成功缓存
	 *
	 * @return 设置值
	 */
	boolean isRequireExplicitSave() {
		return this.requireExplicitSave;
	}

	/**
	 * 获取持久化实现类，如果未自定义设置
	 * 则默认获取代理持久化类 并且执行 设置 持久化实现类
	 * {@link RequestAttributeSecurityContextRepository}
	 * {@link HttpSessionSecurityContextRepository}
	 *
	 * @return 持久化实现类
	 */
	SecurityContextRepository getSecurityContextRepository() {
		SecurityContextRepository securityContextRepository = getBuilder()
				.getSharedObject(SecurityContextRepository.class);
		if (securityContextRepository == null) {
			securityContextRepository = new DelegatingSecurityContextRepository(
					new RequestAttributeSecurityContextRepository(), new HttpSessionSecurityContextRepository());
		}
		return securityContextRepository;
	}

	/**
	 * 执行配置
	 *
	 * @param http 构建对象
	 */
	@Override
	@SuppressWarnings("unchecked")
	public void configure(H http) {
		// 获取持久化实现类
		SecurityContextRepository securityContextRepository = getSecurityContextRepository();
		// 如果需要显示设置登录成功持久化内存
		// 则创建 SecurityContextHolderFilter 并将该过滤器新增到过滤牵连中
		// 否则则使用 SecurityContextPersistenceFilter 并将该过滤器新增到过滤牵连中
		if (this.requireExplicitSave) {
			SecurityContextHolderFilter securityContextHolderFilter = postProcess(
					new SecurityContextHolderFilter(securityContextRepository));
			securityContextHolderFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
			http.addFilter(securityContextHolderFilter);
		} else {
			SecurityContextPersistenceFilter securityContextFilter = new SecurityContextPersistenceFilter(securityContextRepository);
			securityContextFilter.setSecurityContextHolderStrategy(getSecurityContextHolderStrategy());
			SessionManagementConfigurer<?> sessionManagement = http.getConfigurer(SessionManagementConfigurer.class);
			SessionCreationPolicy sessionCreationPolicy = (sessionManagement != null)
					? sessionManagement.getSessionCreationPolicy() : null;
			if (SessionCreationPolicy.ALWAYS == sessionCreationPolicy) {
				securityContextFilter.setForceEagerSessionCreation(true);
				http.addFilter(postProcess(new ForceEagerSessionCreationFilter()));
			}
			securityContextFilter = postProcess(securityContextFilter);
			http.addFilter(securityContextFilter);
		}
	}

}
